﻿using System;
using System.Drawing;
using System.IO;
using Firestarter.DB.Schema.BO;
using FireStarterModeller.UI.Dialogs;
using Habanero.Base;
using Habanero.BO.ClassDefinition;
using Habanero.Faces.Base;
using Habanero.Faces.Win;

namespace FireStarterModeller.UI.DatabaseConnection
{

    public class DatabaseConnectionInfoEditorControl : UserControlWin, IBOEditorControl
    {
        private readonly IControlFactory _controlFactory;
        private IPanelInfo _vendorDropDownOnlyPanelInfo;
        private IPanelInfo _remoteDatabaseConnectionPanelInfo;
        private IPanelInfo _filebasedDatabaseConnectionPanelInfo;
        private IPanel _noVendorSelectedPanel;
        private IPanel _fileBasedDatabasePanel;
        private DatabaseConnectionInfo _databaseConnectionInfo;

        ///<summary>
        /// The Constructor for <see cref="BOEditorControlWin{T}"/>
        ///</summary>
        ///<param name="controlFactory"></param>
        public DatabaseConnectionInfoEditorControl(IControlFactory controlFactory)
        {
            // _databaseConnectionInfo = CreateUnsavedValidDatabaseConnectionInfo();
            if (controlFactory == null) throw new ArgumentNullException("controlFactory");
            _controlFactory = controlFactory;
            SetupControls();
            SetSize();
            SetEnableState();
        }


        public IControlFactory ControlFactory
        {
            get { return _controlFactory; }
        }

        public IPanel NoVendorSelectedPanel
        {
            get { return _noVendorSelectedPanel; }
        }

        public IPanel FileBasedDatabasePanel
        {
            get { return _fileBasedDatabasePanel; }
        }

        public IPanel RemoteDatabasePanel
        {
            get { return _remoteDatabaseConnectionPanelInfo.Panel; }
        }

        private void SetupControls()
        {
            PanelBuilder panelBuilder = new PanelBuilder(_controlFactory);

            BorderLayoutManager mainLayoutManager = _controlFactory.CreateBorderLayoutManager(this);
            mainLayoutManager.AddControl(GetVendorPanel(panelBuilder), BorderLayoutManager.Position.North);
            mainLayoutManager.AddControl(GetConnectionSettingsGroupBox(panelBuilder), BorderLayoutManager.Position.Centre);
            
        }

        public IGroupBox GetConnectionSettingsGroupBox(PanelBuilder panelBuilder)
        {
            IGroupBox connectionSettingsGroupBox = _controlFactory.CreateGroupBox("Connection Settings");
            connectionSettingsGroupBox.Width = 600;
            connectionSettingsGroupBox.Height = 135;
            FlowLayoutManager connectionSettingsLayoutManager = new FlowLayoutManager(connectionSettingsGroupBox, _controlFactory) { BorderSize = 15 };
            connectionSettingsLayoutManager.AddControl(GetNoVendorSelectedPanel());
            connectionSettingsLayoutManager.AddControl(GetRemoteDatabasePanel(panelBuilder));
            connectionSettingsLayoutManager.AddControl(GetFilebasedDatabasePanel(panelBuilder));
            return connectionSettingsGroupBox;
        }

        private IPanel GetNoVendorSelectedPanel()
        {
            _noVendorSelectedPanel = _controlFactory.CreatePanel();
            _noVendorSelectedPanel.Controls.Add(_controlFactory.CreateLabel("Please select a Vendor."));
            _noVendorSelectedPanel.Visible = false;
            return _noVendorSelectedPanel;
        }

        private IPanel GetVendorPanel(PanelBuilder panelBuilder)
        {
            _vendorDropDownOnlyPanelInfo = panelBuilder.BuildPanelForForm(GetDatabaseConnectionInfoUIForm());
            _vendorDropDownOnlyPanelInfo.BusinessObject = this.DatabaseConnectionInfo;
            _vendorDropDownOnlyPanelInfo.Panel.Height = 25;
            return _vendorDropDownOnlyPanelInfo.Panel;
        }

        private OpenFileDialogExtendedTextBox _fileDialogExtendedTextBox;

        private IPanel GetFilebasedDatabasePanel(PanelBuilder panelBuilder)
        {
            _fileBasedDatabasePanel = _controlFactory.CreatePanel();
            _fileBasedDatabasePanel.Width = 350;
            var layoutManager = new FlowLayoutManager(_fileBasedDatabasePanel, _controlFactory);
            _filebasedDatabaseConnectionPanelInfo = panelBuilder.BuildPanelForForm(GetDatabaseConnectionInfoForFilebasedDatabasesForm());
            _fileDialogExtendedTextBox = GetFileDialogExtendedTextBox(_filebasedDatabaseConnectionPanelInfo);
            SetupOpenFileDialogExtendedTextBoxExtensionFilters(_fileDialogExtendedTextBox);

            _filebasedDatabaseConnectionPanelInfo.BusinessObject = this.DatabaseConnectionInfo;
            layoutManager.AddControl(_filebasedDatabaseConnectionPanelInfo.Panel);
            return _fileBasedDatabasePanel;
        }

        private static void SetupOpenFileDialogExtendedTextBoxExtensionFilters(OpenFileDialogExtendedTextBox openFileDialogExtendedTextBox)
        {
            if (openFileDialogExtendedTextBox == null) return;
            openFileDialogExtendedTextBox.InitialDirectory = "";
            openFileDialogExtendedTextBox.FileExtensions.AddExtensionFilter("mdb", "Microsoft Access");
            openFileDialogExtendedTextBox.FileExtensions.AddExtensionFilter("accdb", "Microsoft Access 2007");
        }

        private static OpenFileDialogExtendedTextBox GetFileDialogExtendedTextBox(IPanelInfo filebasedDatabasePanelInfo)
        {
            PanelInfo.FieldInfo fieldInfo = filebasedDatabasePanelInfo.FieldInfos["Database"];
            return fieldInfo.InputControl as OpenFileDialogExtendedTextBox;
        }


        private IPanel GetRemoteDatabasePanel(PanelBuilder panelBuilder)
        {
            _remoteDatabaseConnectionPanelInfo = panelBuilder.BuildPanelForForm(GetDatabaseConnectionInfoForRemoteDatabasesForm());
            _remoteDatabaseConnectionPanelInfo.BusinessObject = this.DatabaseConnectionInfo;
            _remoteDatabaseConnectionPanelInfo.Panel.Visible = false;
            return _remoteDatabaseConnectionPanelInfo.Panel;
        }

        private static IUIForm GetDatabaseConnectionInfoUIForm()
        {
            return ClassDef.Get<DatabaseConnectionInfo>().GetUIDef("default").UIForm;
        }

        private static IUIForm GetDatabaseConnectionInfoForRemoteDatabasesForm()
        {
            return ClassDef.Get<DatabaseConnectionInfo>().GetUIDef("RemoteDatabases").UIForm;
        }

        private static IUIForm GetDatabaseConnectionInfoForFilebasedDatabasesForm()
        {
            return ClassDef.Get<DatabaseConnectionInfo>().GetUIDef("FilebasedDatabases").UIForm;
        }

        private void SetSize()
        {
            //this.Size = new Size(_panelInfo.Panel.Width + 10, _panelInfo.MinimumPanelHeight);
            //this.MinimumSize = new Size(_panelInfo.Panel.Width + 10, _panelInfo.MinimumPanelHeight);
        }

        public DatabaseConnectionInfo DatabaseConnectionInfo
        {
            get { return _databaseConnectionInfo; }
            private set
            {
                if (_databaseConnectionInfo != null) _databaseConnectionInfo.PropertyUpdated -= DatabaseConnectionInfo_OnPropertyUpdated;
                _databaseConnectionInfo = value;
                if (_databaseConnectionInfo != null) _databaseConnectionInfo.PropertyUpdated += DatabaseConnectionInfo_OnPropertyUpdated;
                BindDatabaseConnectionInfoToInfoPanels();
                UpdateDatabaseConnectionPanelControls();
                _fileDialogExtendedTextBox.InitialDirectory = GetInitialDirectory();
                WithEveryPanelInfo(panelInfo => panelInfo.UpdateErrorProvidersErrorMessages());
                SetEnableState();
            }
        }

        private string GetInitialDirectory()
        {
            const string backSlash = @"\";
            if (_databaseConnectionInfo == null || _databaseConnectionInfo.Database == null || (!_databaseConnectionInfo.Database.Contains(backSlash))) return "";
            return Path.GetDirectoryName( _databaseConnectionInfo.Database);
        }

        private void BindDatabaseConnectionInfoToInfoPanels()
        {
            WithEveryPanelInfo(panelInfo => panelInfo.BusinessObject = _databaseConnectionInfo );
        }

        private void DatabaseConnectionInfo_OnPropertyUpdated(object sender, BOPropUpdatedEventArgs e)
        {
            if (e.Prop.PropertyName != "Vendor") return;
            UpdateDatabaseConnectionPanelControls();
        }

        private static bool IsFilebasedDatabase(string databaseVendor)
        {
            if (String.IsNullOrEmpty(databaseVendor)) return false;
            return databaseVendor.ToLower().Contains("access");
        }

        private void UpdateDatabaseConnectionPanelControls()
        {
            string databaseVendor = "";
            if (DatabaseConnectionInfo != null) databaseVendor = DatabaseConnectionInfo.Vendor;

            var isEmptyDatabaseVendor = string.IsNullOrEmpty(databaseVendor);
            var isFilebasedDatabase = IsFilebasedDatabase(databaseVendor);
            _noVendorSelectedPanel.Visible = isEmptyDatabaseVendor;
            _remoteDatabaseConnectionPanelInfo.Panel.Visible = !isEmptyDatabaseVendor && !isFilebasedDatabase;
            _fileBasedDatabasePanel.Visible = !isEmptyDatabaseVendor && isFilebasedDatabase;
        }

        /// <summary>
        /// Gets or sets the business object being represented
        /// </summary>
        public virtual IBusinessObject BusinessObject
        {
            get { return DatabaseConnectionInfo; }
            set { DatabaseConnectionInfo = (DatabaseConnectionInfo) value; }
        }
        /// <summary>
        /// Sets the forms enabled state.
        /// </summary>
        protected virtual void SetEnableState()
        {
            var enabled = BusinessObject != null;
            this.Enabled = enabled;
            WithEveryPanelInfo(panelInfo =>
            {
                panelInfo.Panel.Enabled = this.Enabled;
                panelInfo.ControlsEnabled = this.Enabled;

            });
        }

        /// <summary>
        /// Displays any errors or invalid fields associated with the BusinessObjectInfo
        /// being edited.  A typical use would involve activating the ErrorProviders
        /// on a BO panel.
        /// </summary>
        public void DisplayErrors()
        {
            ApplyChangesToBusinessObject();
        }

        /// <summary>
        /// Hides all the error providers.  Typically used where a new object has just
        /// been added and the interface is being cleaned up.
        /// </summary>
        public void ClearErrors()
        {
            WithEveryPanelInfo(info => info.ClearErrorProviders());
        }

        #region Implementation of IBOEditorControl

        /// <summary>
        /// Applies any changes that have occured in any of the Controls on this control's to their related
        /// Properties on the Business Object.
        /// </summary>
        public void ApplyChangesToBusinessObject()
        {
            WithEveryPanelInfo(info => info.ApplyChangesToBusinessObject());
        }

        private void WithEveryPanelInfo(Action<IPanelInfo> action)
        {
            action(_vendorDropDownOnlyPanelInfo);
            action(_filebasedDatabaseConnectionPanelInfo);
            action(_remoteDatabaseConnectionPanelInfo);
        }

        /// <summary>
        /// Does the business object controlled by this control or any of its Aggregate or Composite children have and Errors.
        /// </summary>
        public bool HasErrors
        {
            get { return this.BusinessObject == null ? false : !this.BusinessObject.IsValid(); }
        }

        /// <summary>
        /// Does the Business Object controlled by this control or any of its Aggregate or Composite children have and warnings.
        /// </summary>
        public bool HasWarning
        {
            get { throw new System.NotImplementedException(); }
        }

        /// <summary>
        ///  Returns a list of all warnings for the business object controlled by this control or any of its children.
        /// </summary>
        public ErrorList Errors
        {
            get { throw new System.NotImplementedException(); }
        }

        /// <summary>
        /// Does the business object being managed by this control have any edits that have not been persisted.
        /// </summary>
        /// <returns></returns>
        public bool IsDirty
        {
            get
            {
                ApplyChangesToBusinessObject();
                return this.BusinessObject == null ? false : this.BusinessObject.Status.IsDirty;
            }
        }

        /// <summary>
        /// Returns a list of all warnings for the business object controlled by this control or any of its children.
        /// </summary>
        /// <returns></returns>
        public ErrorList Warnings
        {
            get { throw new System.NotImplementedException(); }
        }

        #endregion


    }
}
